namespace ScrumSprintMonitor.Wpf.Application
{
	#region #using Directives

	using System.Collections.Generic;
	using System.IO;
	using System.Reflection;
	using System.Windows.Forms;

	using Implementation;
	using Implementation.AvailableTimeCalculator;
	using Implementation.Configuration;

	using Infrastructure;
	using Infrastructure.Configuration;

	using Ninject.Core;
	using Ninject.Core.Behavior;
	using Ninject.Core.Parameters;

	using UI.Wpf;

	#endregion

	internal class NinjectAppConfigurationDependentModule : StandardModule
	{
		/// <summary>
		/// Loads the module into the kernel.
		/// </summary>
		public override void Load()
		{
			SetupRuntimeBindings();
		}

		private void SetupRuntimeBindings()
		{
			var connection = Kernel.Get<IConnectionProvider>().ProvideConnectionTo(Settings.Default.TfsServerName, true);

			Bind<IReportableData>().To<ReportableData>().Using<SingletonBehavior>().WithArgument("connection", connection);
			Bind<ISprint>().To<Sprint>().WithArgument("connection", connection);
			Bind<ITeamMember>().To<TeamMember>();
			Bind<ITeamMemberRemainingWorkload>().To<TeamMemberRemainingWorkload>();
			Bind<IRemainingWorkStatusEvaluator>().To<RemainingWorkStatusEvaluator>().Using<SingletonBehavior>();
			Bind<ISprintBacklogCountSnapshot>().To<SprintBacklogCountSnapshot>();
			if (Settings.Default.EnableOutlookIntegration)
			{
				Bind<ITeamMemberAvailableTimeCalculator>().To<FreeBusyTeamMemberAvailableTimeCalculator>().Using<SingletonBehavior>();
				Bind<ITeamMemberFreeBusyInfo>().To<TeamMemberOutlookFreeBusyInfo>().Using<SingletonBehavior>();
				Bind<IFreeBusyInfoConfiguration>().To<OutlookFreeBusyInfoConfiguration>().Using<SingletonBehavior>();
			}
			else
			{
				Bind<ITeamMemberAvailableTimeCalculator>().To<SimpleTeamMemberAvailableTimeCalculator>().Using<SingletonBehavior>();
			}

			var workItemInterpretationConfiguration = new WorkItemInterpretationConfiguration
			                                          	{
			                                          		AllowUnestimatedWorkItems =
			                                          			!Settings.Default.ReportUnestimatedSprintBacklogItems
			                                          	};
			Bind<IWorkItemInterpretationConfiguration>().ToConstant(workItemInterpretationConfiguration);

			var shellLayoutConfiguration = new ShellLayoutConfiguration(SystemInformation.MonitorCount > 1, !Bootstrapper.Debug,
			                                                            Settings.Default.ActiveSprintMode);
			Bind<IShellLayoutConfiguration>().ToConstant(shellLayoutConfiguration);

			SetupConfigurationBindings();
			SetupPresentationSettingsBindings();
			SetupTeamInformationBindings();
		}

		private void SetupPresentationSettingsBindings()
		{
			string fullPath = Path.GetFullPath(Settings.Default.PresentationConfigurationFilePath);

			if (!File.Exists(fullPath))
			{
				throw new FileNotFoundException(
					string.Format("Could not find the presentation settings file at {0}.", Settings.Default.PresentationConfigurationFilePath), fullPath);
			}

			Bind<IPresentationConfiguration>().To<StreamBasedPresentationConfiguration>().Using<SingletonBehavior>().WithArgument("streamProvider",
			                                                                                                                      Kernel.Get
			                                                                                                                      	<FileDataStreamProvider>(
			                                                                                                                      	With.Parameters.
			                                                                                                                      		ConstructorArgument(
			                                                                                                                      		"filePath", fullPath)));
		}

		private void SetupConfigurationBindings()
		{
			string fullPath = Path.GetFullPath(Settings.Default.ConfigurationFilePath);

			if (!File.Exists(fullPath))
			{
				throw new FileNotFoundException(string.Format("Could not find the configuration file at {0}.", Settings.Default.ConfigurationFilePath), fullPath);
			}

			Bind<ISprintConfiguration>().To<StreamBasedSprintConfiguration>().Using<SingletonBehavior>().WithArgument("streamProvider",
			                                                                                                          Kernel.Get<FileDataStreamProvider>(
			                                                                                                          	With.Parameters.ConstructorArgument(
			                                                                                                          		"filePath", fullPath)));
		}

		private void SetupTeamInformationBindings()
		{
			string fullPath = Path.GetFullPath(Settings.Default.TeamMembersConfigurationFilePath);

			if (!File.Exists(fullPath))
			{
				throw new FileNotFoundException(
					string.Format("Could not find the team information xml file at {0}.", Settings.Default.TeamMembersConfigurationFilePath), fullPath);
			}

			IDataStreamProvider xsdStreamProvider = null;
			string xsdPath = Path.Combine(Path.GetDirectoryName(Settings.Default.TeamMembersConfigurationFilePath), @"team-info.xsd");
			if (!File.Exists(xsdPath))
			{
				xsdPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"team-info.xsd");
			}
			if (File.Exists(xsdPath))
			{
				xsdStreamProvider = Kernel.Get<FileDataStreamProvider>(With.Parameters.ConstructorArgument("filePath", xsdPath));
			}
			var teamMemberInfoProviderParams = new Dictionary<string, object>
			                                   	{
			                                   		{
			                                   			"xmlStreamProvider",
			                                   			Kernel.Get<FileDataStreamProvider>(
			                                   			With.Parameters.ConstructorArgument("filePath", fullPath))
			                                   			},
			                                   		{"xsdStreamProvider", xsdStreamProvider}
			                                   	};

			Bind<ITeamMemberInfoProvider>().To<XmlStreamBasedTeamInfoProvider>().Using<SingletonBehavior>().WithArguments(teamMemberInfoProviderParams);

			Bind<ITeamMemberInformation>().To<TeamMemberInformation>();
		}
	}
}